// src/composables/audioEngine.js
import { reactive, ref } from "vue";
import { useStore } from "@/stores/data"; // 读取 userConfig

const WS_AUDIO_URL = `ws://192.168.1.153:8000/ws/audio`;
const MAX_MAIN = 7;
const MAX_EVENT = 100;

function token() {
  const raw = localStorage.getItem("token") || "";
  const s = raw.trim();
  if (!s || s === "null" || s === "undefined" || s === "None") return "";
  return s.toLowerCase().startsWith("bearer ") ? s.slice(7).trim() : s;
}
function makeUrl() {
  const t = token();
  return t ? `${WS_AUDIO_URL}?token=${encodeURIComponent(t)}` : WS_AUDIO_URL;
}
function pick(arr, fallback) {
  if (!Array.isArray(arr) || arr.length === 0) return fallback;
  return arr[Math.floor(Math.random() * arr.length)];
}
function rand(min, max) {
  if (max < min) [min, max] = [max, min];
  return min + Math.random() * (max - min);
}
function replaceBanned(text, list) {
  let out = text;
  (list || []).forEach(it => {
    if (!it || !it.origin) return;
    try {
      const re = new RegExp(it.origin.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), "g");
      out = out.replace(re, it.target || "");
    } catch {}
  });
  return out;
}

const state = reactive({
  wsStatus: "idle",      // idle | connecting | open | closed | blocked
  lastError: "",
  mainList: [],          // {id,url,text,qtype,mime,size}
  eventList: [],
  mainPlaying: false,
  eventPlaying: false,
  maxMain: MAX_MAIN,
  maxEvent: MAX_EVENT,
});

let ws = null;
let inflight = 0;        // 串行合成：0/1
let pendingMeta = null;
let pendingResolve = null;

// 两个全局 audio（常驻）
let mainEl = null;
let eventEl = null;

// 主话术恢复点
let resumeMain = null;
// 主话术间隔定时器
let mainGapTimer = null;

// 每类事件的上次触发时间（限流）
const lastEventAt = {};

// ========= WS: /ws/audio =========
function connectAudioWS() {
  if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) return;
  const t = token();
  if (!t) { state.wsStatus = "blocked"; state.lastError = "缺少令牌"; return; }

  state.wsStatus = "connecting"; state.lastError = "";
  ws = new WebSocket(makeUrl());
  ws.binaryType = "arraybuffer";

  ws.onopen = () => { state.wsStatus = "open"; };
  ws.onerror = () => {};
  ws.onclose = () => { state.wsStatus = "closed"; };

  ws.onmessage = (ev) => {
    if (typeof ev.data === "string") {
      try {
        const msg = JSON.parse(ev.data);
        if (msg.type === "audio_meta") {
          pendingMeta = msg; // 等后面的二进制
        }
      } catch {}
    } else {
      if (!pendingMeta || !pendingResolve) return;
      const mime = pendingMeta.mime || "audio/wav";
      const blob = new Blob([ev.data], { type: mime });
      const url = URL.createObjectURL(blob);
      const item = {
        id: pendingMeta.id,
        qtype: pendingMeta.qtype || "main",
        text: pendingMeta.text || "",
        mime,
        size: Number(pendingMeta.size || blob.size || 0),
        blob,
        url,
      };
      inflight = Math.max(0, inflight - 1);
      const ok = pendingResolve; pendingResolve = null; pendingMeta = null;
      ok(item);
    }
  };
}
function disconnectAudioWS() {
  if (ws) { try { ws.close(); } catch{} }
  ws = null; state.wsStatus = "closed";
}
function sendSynth(text, qtype) {
  if (!ws || ws.readyState !== WebSocket.OPEN) throw new Error("audio ws 未连接");
  ws.send(JSON.stringify({ type: "synthesize", qtype, text }));
}
function synthesize(text, qtype) {
  if (state.wsStatus !== "open") return Promise.reject(new Error("audio ws 未连接"));
  return new Promise((resolve, reject) => {
    const send = () => {
      inflight++;
      pendingResolve = resolve;
      try { sendSynth(text, qtype); } catch (e) {
        inflight = Math.max(0, inflight - 1);
        pendingResolve = null; reject(e);
      }
    };
    const wait = () => {
      if (inflight === 0) return send();
      setTimeout(wait, 30);
    };
    wait();
  });
}

// ========= 全局 audio =========
function ensureGlobalAudios() {
  if (!mainEl) {
    mainEl = document.createElement("audio");
    mainEl.preload = "auto"; mainEl.autoplay = true;
    mainEl.setAttribute("playsinline", "true");
    mainEl.setAttribute("webkit-playsinline", "true");
    mainEl.style.display = "none";
    document.body.appendChild(mainEl);
    bindMainEvents(mainEl);
  }
  if (!eventEl) {
    eventEl = document.createElement("audio");
    eventEl.preload = "auto";
    eventEl.setAttribute("playsinline", "true");
    eventEl.setAttribute("webkit-playsinline", "true");
    eventEl.style.display = "none";
    document.body.appendChild(eventEl);
    bindEventEvents(eventEl);
  }
}
function attachMainAudio(el) {
  ensureGlobalAudios();
  if (mainEl && mainEl !== el) {
    try { mainEl.pause(); } catch {}
    mainEl.remove();
  }
  mainEl = el;
  bindMainEvents(mainEl);
}
function attachEventAudio(el) {
  ensureGlobalAudios();
  if (eventEl && eventEl !== el) {
    try { eventEl.pause(); } catch {}
    eventEl.remove();
  }
  eventEl = el;
  bindEventEvents(eventEl);
}
function unlockAudio() {
  ensureGlobalAudios();
  try { mainEl.play().catch(()=>{}); } catch {}
  try { eventEl.play().catch(()=>{}); } catch {}
  try { mainEl.pause(); } catch {}
  try { eventEl.pause(); } catch {}
}

// ========= 播放调度（事件优先）=========
function playOn(el, item) {
  el.src = item.url;
  el.play().catch(()=>{});
}
function tryPlayNext() {
  // 如果事件在播，等等
  if (state.eventPlaying) return;

  // 有待播事件：抢占
  if (state.eventList.length > 0) {
    if (mainEl && !mainEl.paused) {
      resumeMain = { url: mainEl.src, time: mainEl.currentTime || 0 };
      try { mainEl.pause(); } catch {}
      state.mainPlaying = false;
    }
    if (mainGapTimer) { clearTimeout(mainGapTimer); mainGapTimer = null; }
    const item = state.eventList.shift();
    playOn(eventEl, item);
    state.eventPlaying = true;
    return;
  }

  // 没事件：恢复或播主话术
  if (resumeMain) {
    mainEl.src = resumeMain.url;
    try { mainEl.currentTime = resumeMain.time; } catch {}
    resumeMain = null;
    mainEl.play().catch(()=>{});
    state.mainPlaying = true;
    return;
  }

  if (!state.mainPlaying && state.mainList.length > 0) {
    const app = useStore();
    const space = app.userConfig?.mainTxtSpace || [0.2, 0.3];
    const min = Number(space[0] || 0.2), max = Number(space[1] || 0.3);
    const delay = Math.max(0, Math.round(rand(min, max) * 1000));
    if (mainGapTimer) { clearTimeout(mainGapTimer); mainGapTimer = null; }
    mainGapTimer = setTimeout(() => {
      const it = state.mainList.shift();
      playOn(mainEl, it);
      state.mainPlaying = true;
    }, delay);
  }
}
function bindMainEvents(el) {
  el.addEventListener("ended", () => {
    state.mainPlaying = false;
    fillMain().finally(()=> tryPlayNext());
  });
  el.addEventListener("error", () => {
    state.mainPlaying = false;
    tryPlayNext();
  });
  el.addEventListener("play", () => { state.mainPlaying = true; });
  el.addEventListener("pause", () => { state.mainPlaying = false; });
}
function bindEventEvents(el) {
  el.addEventListener("ended", () => {
    state.eventPlaying = false;
    tryPlayNext();
  });
  el.addEventListener("error", () => {
    state.eventPlaying = false;
    tryPlayNext();
  });
  el.addEventListener("play", () => { state.eventPlaying = true; });
}

// ========= 生产：主话术补货 & 事件推入 =========
let mainIdx = 0;
async function fillMain() {
  ensureGlobalAudios();
  if (state.wsStatus !== "open") return;
  const app = useStore();

  const list = Array.isArray(app.userConfig?.mainTxt) && app.userConfig.mainTxt.length > 0
    ? app.userConfig.mainTxt
    : ["欢迎来到直播间～", "点点关注不迷路～", "喜欢的朋友多多互动哦～"];

  while (state.mainList.length < state.maxMain) {
    const raw = String(list[mainIdx % list.length] || "").trim();
    mainIdx++;
    if (!raw) break;
    const text = replaceBanned(raw, app.userConfig?.bannedlist || []);
    const item = await synthesize(text, "main").catch(()=>null);
    if (!item) break;
    state.mainList.push(item);
  }
}

async function pushEventByText(text, qtype) {
  ensureGlobalAudios();
  if (state.wsStatus !== "open") return;
  const t = (text || "").trim();
  if (!t) return;
  const app = useStore();
  const safe = replaceBanned(t, app.userConfig?.bannedlist || []);
  const item = await synthesize(safe, qtype || "interrupt").catch(()=>null);
  if (!item) return;
  if (state.eventList.length >= state.maxEvent) {
    const old = state.eventList.shift();
    if (old && old.url) URL.revokeObjectURL(old.url);
  }
  state.eventList.push(item);
  tryPlayNext();
}

// ========= 直播事件入口（限流 + 文案池挑一句）=========
function eventLimitSec(qt, cfg) {
  if (qt === "welcome")  return Number(cfg.welcomeSpace ?? 30);
  if (qt === "like")     return Number(cfg.likeTxtSpace ?? 60);
  if (qt === "gift")     return Number(cfg.giftTxtSpace ?? 30);
  if (qt === "follow")   return Number(cfg.loveTxtSpace ?? 15);
  if (qt === "interrupt")return Number(cfg.dsSpace ?? 2);
  return 0;
}
function pickEventText(qt, e, cfg) {
  if (qt === "welcome")  return String(pick(cfg.welcometxt, "欢迎来到直播间～") || "");
  if (qt === "like")     return String(pick(cfg.likeTxt, "谢谢你的点赞～") || "");
  if (qt === "gift")     return String(pick(cfg.giftTxt, "谢谢礼物支持～") || "");
  if (qt === "follow")   return String(pick(cfg.loveTxt, "感谢你的关注～") || "");
  if (qt === "interrupt") {
    const user = e.user_name || e.user || "";
    const text = e.content || e.text || "";
    if (!text) return null;
    return (user ? (user + "说：") : "") + text;
  }
  return null;
}
async function onDanmuEvent(msg) {
  if (!msg || msg.type !== "danmu_event") return;
  const e = msg.data || msg;
  const et = String(e.type || e.method || "").toLowerCase();
  const map = {
    "welcome":"welcome", "member_enter":"welcome", "webcastmembermessage":"welcome",
    "like":"like", "webcastlikemessage":"like",
    "gift":"gift", "webcastgiftmessage":"gift",
    "follow":"follow", "webcastsocialmessage":"follow",
    "chat":"interrupt", "webcastchatmessage":"interrupt"
  };
  const qt = map[et];
  if (!qt) return;

  const app = useStore();
  const cfg = app.userConfig || {};
  const now = Date.now();
  const gap = eventLimitSec(qt, cfg) * 1000;
  const last = lastEventAt[qt] || 0;
  if (now - last < gap) return; // 限流
  lastEventAt[qt] = now;

  const t = pickEventText(qt, e, cfg);
  if (!t) return;
  await pushEventByText(t, qt);
}

// ========= 暴露 API =========
export function audioEngine() {
  return {
    state,
    connectAudioWS,
    disconnectAudioWS,
    unlockAudio,
    attachMainAudio,
    attachEventAudio,
    fillMain,
    pushEventByText,
    synthesize,
    tryPlayNext,
    onDanmuEvent,
  };
}
